package wmysql

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
)

type WOffer struct {
	db *sql.DB
}

type Advertiser struct {
	Id      int
	Token   string
	User    string
	Mail    string
	Phone   string
	Country string
}

type Publisher struct {
	Id      int
	Token   string
	User    string
	Mail    string
	Phone   string
	Country string
}

type Advapp struct {
	Id           int
	AdvertiserId int
	Platform     int
	Package      string
	Third        string
	Icon         string
	ClickUrl     string
}

type Campaign struct {
	Id       int
	AdvappId int
	Price    float64
	PriceOut float64
	CutRate  float64
	Status   int
	DailyCap int
	Budget   int
	Regions  string
	Stime    int
	Etime    int
	Osmin    int
	Osmax    int
	Black    string
	White    string
}

type PublisherCampaign struct {
	PublisherId int
	CampaignId  int
	PriceOut    float64
	CutRate     float64
	Status      int
	DailyCap    int
}

func (o *WOffer) Init(uri string, maxIdleConn int, maxOpenConn int) error {
	db, err := sql.Open("mysql", uri)
	if err != nil {
		return err
	}
	db.SetMaxOpenConns(maxOpenConn)
	db.SetMaxIdleConns(maxIdleConn)
	if err := db.Ping(); err != nil {
		return err
	}
	o.db = db
	return nil
}

func (o *WOffer) InsertAdvertiser(a *Advertiser) (int64, error) {
	res, err := o.db.Exec(
		`INSERT INTO advertiser (token, user, mail, phone, country) VALUES (?, ?, ?, ?, ?)
		ON DUPLICATE KEY UPDATE mail = ?, phone = ?, country = ?`,
		a.Token, a.User, a.Mail, a.Phone, a.Country,
		a.Mail, a.Phone, a.Country,
	)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (o *WOffer) InsertPublisher(p *Publisher) (int64, error) {
	res, err := o.db.Exec(
		`INSERT INTO publisher (token, user, mail, phone, country) VALUES (?, ?, ?, ?, ?)
		ON DUPLICATE KEY UPDATE mail = ?, phone = ?, country = ?`,
		p.Token, p.User, p.Mail, p.Phone, p.Country,
		p.Mail, p.Phone, p.Country,
	)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (o *WOffer) InsertAdvapp(a *Advapp) (int64, error) {
	res, err := o.db.Exec(
		`INSERT INTO advapp (advertiser_id, package, platform, third, icon, click_url) VALUES (?, ?, ?, ?, ?, ?)
		ON DUPLICATE KEY UPDATE platform = ?, third = ?, icon = ?, click_url = ?`,
		a.AdvertiserId, a.Package, a.Platform, a.Third, a.Icon, a.ClickUrl,
		a.Platform, a.Third, a.Icon, a.ClickUrl,
	)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (o *WOffer) InsertCampaign(c *Campaign) (int64, error) {
	res, err := o.db.Exec(
		`INSERT INTO campaign (advapp_id, price, price_out, cut_rate, status, daily_cap, budget, regions, stime, etime, osmin, osmax, black, white) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
		c.AdvappId, c.Price, c.PriceOut, c.CutRate, c.Status, c.DailyCap, c.Budget, c.Regions, c.Stime, c.Etime, c.Osmin, c.Osmax, c.Black, c.White,
	)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (o *WOffer) InsertPublisherCampaign(pc *PublisherCampaign) (int64, error) {
	res, err := o.db.Exec(
		`INSERT INTO publisher_campaign (publisher_id, campaign_id, price_out, cut_rate, status, daily_cap) VALUES (?, ?, ?, ?, ?, ?)`,
		pc.PublisherId, pc.CampaignId, pc.PriceOut, pc.CutRate, pc.Status, pc.DailyCap,
	)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (o *WOffer) SelectAdvertiserByToken(token string) (*Advertiser, error) {
	a := &Advertiser{}
	row := o.db.QueryRow(`SELECT id, token, user, mail, phone, country FROM advertiser WHERE token = ?`, token)
	if err := row.Scan(&a.Id, &a.Token, &a.User, &a.Mail, &a.Phone, &a.Country); err != nil {
		return nil, err
	}

	return a, nil
}

func (o *WOffer) SelectPublisherByToken(token string) (*Publisher, error) {
	p := &Publisher{}
	row := o.db.QueryRow(`SELECT id, token, user, mail, phone, country FROM publisher WHERE token = ?`, token)
	if err := row.Scan(&p.Id, &p.Token, &p.User, &p.Mail, &p.Phone, &p.Country); err != nil {
		return nil, err
	}

	return p, nil
}

func (o *WOffer) SelectAdvappById(id int) (*Advapp, error) {
	a := &Advapp{}
	row := o.db.QueryRow(`SELECT id, advertiser_id, platform, package, third, icon, click_url FROM advapp WHERE id = ?`, id)
	if err := row.Scan(&a.Id, &a.AdvertiserId, &a.Platform, &a.Package, &a.Third, &a.Icon, &a.ClickUrl); err != nil {
		return nil, err
	}

	return a, nil
}

func (o *WOffer) SelectAdvappByAdvertiserPackage(advertiserId int, pkg string) (*Advapp, error) {
	a := &Advapp{}
	row := o.db.QueryRow(`SELECT id, advertiser_id, platform, package, third, icon, click_url FROM advapp WHERE advertiser_id = ? AND package = ?`, advertiserId, pkg)
	if err := row.Scan(&a.Id, &a.AdvertiserId, &a.Platform, &a.Package, &a.Third, &a.Icon, &a.ClickUrl); err != nil {
		return nil, err
	}

	return a, nil
}

func (o *WOffer) SelectCampaignById(id int) (*Campaign, error) {
	c := &Campaign{}
	row := o.db.QueryRow(`SELECT id, advapp_id, price, price_out, cut_rate, status, daily_cap, budget, regions, stime, etime, osmin, osmax, black, white FROM campaign WHERE id = ?`, id)
	if err := row.Scan(&c.Id, &c.AdvappId, &c.Price, &c.PriceOut, &c.CutRate, &c.Status, &c.DailyCap, &c.Budget, &c.Regions, &c.Stime, &c.Etime, &c.Osmin, &c.Osmax, &c.Black, &c.White); err != nil {
		return nil, err
	}

	return c, nil
}

func (o *WOffer) SelectCampaignsByAdvapp(advappId int) ([]*Campaign, error) {
	cs := []*Campaign{}
	rows, err := o.db.Query(`SELECT id, advapp_id, price, price_out, cut_rate, status, daily_cap, budget, regions, stime, etime, osmin, osmax, black, white FROM campaign WHERE advapp_id = ?`, advappId)
	if err != nil {
		return nil, err
	}
	for rows.Next() {
		c := &Campaign{}
		if err := rows.Scan(&c.Id, &c.AdvappId, &c.Price, &c.PriceOut, &c.CutRate, &c.Status, &c.DailyCap, &c.Budget, &c.Regions, &c.Stime, &c.Etime, &c.Osmin, &c.Osmax, &c.Black, &c.White); err != nil {
			return nil, err
		}
		cs = append(cs, c)
	}

	return cs, nil
}

func (o *WOffer) SelectPubCampaignByPC(publisherId, campaignId int) (*PublisherCampaign, error) {
	pc := &PublisherCampaign{}
	row := o.db.QueryRow(`SELECT publisher_id, campaign_id, price_out, cut_rate, status, daily_cap FROM publisher_campaign WHERE publisher_id = ? and campaign_id=?`, publisherId, campaignId)
	if err := row.Scan(&pc.PublisherId, &pc.CampaignId, &pc.PriceOut, &pc.CutRate, &pc.Status, &pc.DailyCap); err != nil {
		return nil, err
	}
	return pc, nil
}

func (o *WOffer) DeleteAdvertiserById(id int) (int64, error) {
	res, err := o.db.Exec(`DELETE FROM advertiser WHERE id = ?`, id)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (o *WOffer) DeletePublisherById(id int) (int64, error) {
	res, err := o.db.Exec(`DELETE FROM publisher WHERE id = ?`, id)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (o *WOffer) DeleteAdvappById(id int) (int64, error) {
	res, err := o.db.Exec(`DELETE FROM advapp WHERE id = ?`, id)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (o *WOffer) DeleteCampaignById(id int) (int64, error) {
	res, err := o.db.Exec(`DELETE FROM campaign WHERE id = ?`, id)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (o *WOffer) DeletePublisherCampaignByPC(publisherId, campaignId int) (int64, error) {
	res, err := o.db.Exec(`DELETE FROM publisher_campaign publisher_id = ? and campaign_id=?`, publisherId, campaignId)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}
